#include "EthDot3Layer.h"
#include "EndianPortable.h"
#include "PayloadLayer.h"
#include "LLCLayer.h"

namespace pcpp
{

	EthDot3Layer::EthDot3Layer(const MacAddress& sourceMac, const MacAddress& destMac, uint16_t length) : Layer()
	{
		const size_t headerLen = sizeof(ether_dot3_header);
		m_DataLen = headerLen;
		m_Data = new uint8_t[headerLen];
		memset(m_Data, 0, headerLen);

		ether_dot3_header* ethHdr = (ether_dot3_header*)m_Data;
		destMac.copyTo(ethHdr->dstMac);
		sourceMac.copyTo(ethHdr->srcMac);
		ethHdr->length = be16toh(length);
		m_Protocol = Ethernet;
	}

	void EthDot3Layer::parseNextLayer()
	{
		if (m_DataLen <= sizeof(ether_dot3_header))
			return;

		uint8_t* payload = m_Data + sizeof(ether_dot3_header);
		size_t payloadLen = m_DataLen - sizeof(ether_dot3_header);

		if (LLCLayer::isDataValid(payload, payloadLen))
			m_NextLayer = new LLCLayer(payload, payloadLen, this, m_Packet);
		else
			m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
	}

	std::string EthDot3Layer::toString() const
	{
		return "IEEE 802.3 Ethernet, Src: " + getSourceMac().toString() + ", Dst: " + getDestMac().toString();
	}

	bool EthDot3Layer::isDataValid(const uint8_t* data, size_t dataLen)
	{
		if (dataLen >= sizeof(ether_dot3_header))
		{
			/**
			 * LSAPs: ... Such a length must, when considered as an
			 * unsigned integer, be less than 0x5DC or it could be mistaken as
			 * an Ethertype...
			 *
			 * From: https://tools.ietf.org/html/rfc5342#section-2.3.2.1
			 * More: IEEE Std 802.3 Clause 3.2.6
			 */
			return be16toh(*(uint16_t*)(data + 12)) <= (uint16_t)0x05DC;
		}
		else
		{
			return false;
		}
	}

}  // namespace pcpp
